package com.wx.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.wx.client.SysFileClient;
import com.wx.common.PageParam;
import com.wx.constants.Constants;
import com.wx.constants.RedisKeyPrefix;
import com.wx.domain.dto.DayReportQueryParam;
import com.wx.domain.dto.StatisticsDto;
import com.wx.domain.dto.SysPatientDto;
import com.wx.domain.vo.*;
import com.wx.entity.*;
import com.wx.exception.BusinessException;
import com.wx.mapper.SysPatientMapper;
import com.wx.service.*;
import com.wx.utils.SnowFlakeUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;


/**
 * <p>Title:      SysPatientServiceImpl. </p>
 * <p>Description  </p>
 * <p>Copyright: Copyright (c) 2016</p>
 * <p>Company:    医百科技有限公司 </p>
 *
 * @author         yangwensheng@100doc.com.cn
 * @since      2021-03-03 11:36:07
 */
@Service
public class SysPatientServiceImpl extends BaseServiceImpl<SysPatient> implements SysPatientService {

    @Resource
    private SysPatientMapper sysPatientMapper;

    @Resource
    private SysGeneratorCodeService sysGeneratorCodeService;

    @Resource
    private SysNurseService sysNurseService;

    @Resource
    private SysRangeService sysRangeService;

    @Resource
    private SysRangeHospitalService sysRangeHospitalService;

    @Resource
    private RedisService redisService;

    @Resource
    private SysAddressService sysAddressService;

    @Resource
    private SysFileClient sysFileClient;

    @Resource
    private SysAgreementService sysAgreementService;

    @Resource
    private SysHospitalService sysHospitalService;

    @Resource
    private SysPatientFollowService sysPatientFollowService;

    @Resource
    private SysRangeNurseService sysRangeNurseService;

    @Override
    public List<PatientVo> listPage(SysPatientDto sysPatient){
        return sysPatientMapper.listPage(sysPatient);
    }


    @Override
    public String onlineApplication(SysPatient sysPatient) {
        sysPatient.setJoinType(Constants.JoinType.OFFLINE);
        if(StringUtils.isEmpty(sysPatient.getId())){
            SysPatient qr = new SysPatient();
            qr.setDelFlag(Constants.DELETE_NO);
            qr.setIdNum(sysPatient.getIdNum());
            SysPatient queryPatient = sysPatientMapper.selectOne(qr);
            if(queryPatient != null){
                throw new BusinessException("该身份证号对应的患者信息已经录入到系统中");
            }
            SysPatient qry = new SysPatient();
            qry.setPhone(sysPatient.getPhone());
            qry.setDelFlag(Constants.DELETE_NO);
            SysPatient qp = sysPatientMapper.selectOne(qry);
            if(qp != null){
                throw new BusinessException("该手机号对应的患者信息已经录入到系统中，请更换其它手机号");
            }
            String uuid = sysGeneratorCodeService.fetchUUID(RedisKeyPrefix.PATIENT_KEY, 6, false);
            sysPatient.setJoinCode("XS" + uuid);
            sysPatient.setId(SnowFlakeUtil.getStringId());
            sysPatient.setBirthday(new Date());

            String followCode = sysGeneratorCodeService.fetchUUID(RedisKeyPrefix.PATIENT_FOLLOW_CODE, 6, false);
            sysPatient.setFollowCode("BF" + followCode);

            sysPatientMapper.insertSelective(sysPatient);
        }else{
            int result = sysPatientMapper.updateByPrimaryKeySelective(sysPatient);
            if(result == 0){
                throw new BusinessException("患者信息不存在，请检查参数是否合法");
            }
        }
        return sysPatient.getId();
    }

    @Override
    public int updateStatus(SysPatient sysPatient) {
        if(StringUtils.isEmpty(sysPatient.getId())){
            throw new BusinessException("患者id不能为空");
        }
        if(StringUtils.isEmpty(sysPatient.getIdCardFront())){
            throw new BusinessException("身份证正面的url地址不能为空");
        }
        if(StringUtils.isEmpty(sysPatient.getIdCardBack())){
            throw new BusinessException("身份证反面的url地址不能为空");
        }
        if(StringUtils.isEmpty(sysPatient.getIdNum())){
            throw new BusinessException("身份证号不能为空");
        }
        if(StringUtils.isEmpty(sysPatient.getRealName())){
            throw new BusinessException("姓名不能为空");
        }
        if(sysPatient.getSex() == null){
            throw new BusinessException("性别不能为空");
        }
        if(sysPatient.getBirthday() == null){
            throw new BusinessException("出生日期不能为空");
        }
        SysPatient patient = sysPatientMapper.selectByPrimaryKey(sysPatient.getId());
        if(patient == null){
            throw new BusinessException("查询患者信息不存在");
        }
        if(!patient.getIdNum().equals(sysPatient.getIdNum())){
            throw new BusinessException("解析后的身份证与录入的身份证号不相同，请重新上传进行实名认证");
        }
        if(!patient.getRealName().equals(sysPatient.getRealName())){
            throw new BusinessException("解析后的身份证与录入的姓名不相同，请重新上传进行实名认证");
        }
        if(!patient.getSex().equals(sysPatient.getSex())){
            throw new BusinessException("解析后的身份证与录入的性别不相同，请重新上传进行实名认证");
        }
        sysPatient.setId(patient.getId());
        sysPatient.setStatus(Integer.valueOf(Constants.ENABLE));
        sysPatient.setUpdateDate(new Date());
        return sysPatientMapper.updateByPrimaryKeySelective(sysPatient);
    }

    @Override
    @Transactional
    public int updateAgreement(String id, String openid, String nickName) throws Exception{
        SysPatient patient = sysPatientMapper.selectByPrimaryKey(id);
        if(patient == null){
            throw new BusinessException("查询患者信息不存在");
        }
        SysPatient update = new SysPatient();
        update.setStatus(Integer.valueOf(Constants.ENABLE));
        update.setId(patient.getId());
        update.setAgreement(Integer.valueOf(Constants.ENABLE));
        update.setAuditStatus(Constants.NO);
        update.setDelFlag(Constants.DELETE_NO);
        update.setUpdateDate(new Date());
        update.setUpdateBy(openid);
        update.setUpdater(nickName);

        // 签署协议
        extracted(openid, nickName, patient);
        return sysPatientMapper.updateByPrimaryKeySelective(update);
    }

    /**
     * 签署协议
     *
     * @param openid String
     * @param nickName String
     * @param patient SysPatient
     * @throws IOException
     * @throws DocumentException
     */
    private void extracted(String openid, String nickName, SysPatient patient) throws IOException, DocumentException {
        // 生成pdf文档
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        org.springframework.core.io.Resource[] resources = resolver.getResources("template/patientTemplate.pdf");
        org.springframework.core.io.Resource resource = resources[0];
        InputStream inputStream = resource.getInputStream();
        PdfReader reader = new PdfReader(IOUtils.toByteArray(inputStream));

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        PdfStamper ps = new PdfStamper(reader, bos);

        Map<String,String> params = Maps.newHashMap();
        params.put("patientName", patient.getRealName());
        params.put("patientPhone", patient.getPhone());
        params.put("signYear", DateUtil.format(new Date(),"yyyy"));
        params.put("signMonth", DateUtil.format(new Date(),"MM"));
        params.put("signDay", DateUtil.format(new Date(),"dd"));

        // 中文字体问题
        BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        ArrayList<BaseFont> fontList = new ArrayList<>();
        fontList.add(bf);
        AcroFields acroFields = ps.getAcroFields();
        acroFields.setSubstitutionFonts(fontList);
        //将查询结果封装到Map中再导出
        for (String key : acroFields.getFields().keySet()) {
            acroFields.setField(key, params.get(key));
        }
        ps.setFormFlattening(true);
        ps.close();


//        String saveFilePath = ClassUtils.getDefaultClassLoader().getResource("").getPath();
        String fileName = SnowFlakeUtil.getStringId() + ".pdf";
        File pdfFile = new File(fileName);
        FileOutputStream fos = new FileOutputStream(fileName);
        fos.write(bos.toByteArray());
        fos.close();
        bos.close();

        // 保存文件到对象存储中
        String url = sysFileClient.uploadToTencent(pdfFile, fileName);
        logger.info("===>患者patientName = {},协议上传后的地址为 url = {}", patient.getRealName(), url);


        // 先删除历史协议
        SysAgreement deleteAgreement = new SysAgreement();
        deleteAgreement.setUserType(Constants.YES);
        deleteAgreement.setUserId(patient.getId());
        deleteAgreement.setUpdateBy(openid);
        deleteAgreement.setUpdater(nickName);
        sysAgreementService.updateByUserId(deleteAgreement);

        // 保存协议内容
        SysAgreement sysAgreement = new SysAgreement();
        sysAgreement.setId(SnowFlakeUtil.getStringId());
        sysAgreement.setUserType(Constants.YES);
        sysAgreement.setUserId(patient.getId());
        sysAgreement.setSignTime(new Date());
        sysAgreement.setFileUrl(url);
        sysAgreement.setCreateBy(openid);
        sysAgreement.setCreator(nickName);
        sysAgreement.setUpdateBy(openid);
        sysAgreement.setUpdater(nickName);
        String uuid = sysGeneratorCodeService.fetchUUID(RedisKeyPrefix.PATIENT_AGREEMENT_KEY, 6, false);
        sysAgreement.setSignCode("AG" + uuid);
        sysAgreementService.save(sysAgreement);

        // 删除临时文件
        File file = new File(pdfFile.getPath());
        if (!file.isDirectory()) {
            file.delete();
        }
    }

    @Override
    public String nurseInput(SysPatient sysPatient) {
        sysPatient.setId(SnowFlakeUtil.getStringId());
        SysPatient qr = new SysPatient();
        qr.setIdNum(sysPatient.getIdNum());
        SysPatient queryPatient = sysPatientMapper.selectOne(qr);
        if(queryPatient != null){
            throw new BusinessException("该身份证号对应的患者信息已经录入到系统中");
        }

        SysPatient qry = new SysPatient();
        qry.setDelFlag(Constants.DELETE_NO);
        qry.setPhone(sysPatient.getPhone());
        SysPatient qp = sysPatientMapper.selectOne(qr);
        if(qp != null){
            throw new BusinessException("该手机号对应的患者信息已经录入到系统中，请更换其它手机号");
        }
        String uuid = sysGeneratorCodeService.fetchUUID(RedisKeyPrefix.PATIENT_KEY, 6, false);
        sysPatient.setJoinCode("XX" + uuid);
        sysPatient.setJoinType(Constants.JoinType.NURSE_INPUT);

        String followCode = sysGeneratorCodeService.fetchUUID(RedisKeyPrefix.PATIENT_FOLLOW_CODE, 6, false);
        sysPatient.setFollowCode("BF" + followCode);
        sysPatientMapper.insertSelective(sysPatient);
        return sysPatient.getId();
    }

    @Override
    public PageInfo<SysPatient> listPageByOpenId(PageParam<SysPatient> param, String openId, Integer status) {
        // 先根据openId查询护士信息
        SysNurse sysNurse = sysNurseService.selectByOpenId(openId);
        if(sysNurse == null){
            throw new BusinessException("请先前往患者管理页面进行护士信息的认证");
        }
        // 查询护士所属的范围
        SysRangeNurse sysRangeNurse = sysRangeNurseService.selectByNurseId(sysNurse.getId());
        if(sysRangeNurse == null){
            throw new BusinessException("请联系后台管理员设置您的所属范围");
        }
        // 查询范围所关联的医院信息
        List<SysRangeHospital> sysRangeHospitalList = sysRangeHospitalService.selectByRangeIds(Collections.singletonList(sysRangeNurse.getRangeId()));
        List<String> hospitalIds = sysRangeHospitalList.stream().map(SysRangeHospital::getHospitalId).collect(Collectors.toList());
        // 根据医院id查询已经入组的患者信息
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        SysPatient patient = param.getParam();
        patient.setAuditStatus(status);
        List<SysPatient> patients = sysPatientMapper.selectByHospitalIds(hospitalIds,param.getParam());
        return new PageInfo<>(patients);
    }

    @Override
    public SysPatient getPatientInfoByOpenId(String openId) {
        SysPatient sysPatient = sysPatientMapper.getPatientInfoByOpenId(openId);
        if(sysPatient != null){
            List<SysAddress> sysAddresses = sysAddressService.getAll();
            Map<String, String> addRessMap = sysAddresses.stream().collect(Collectors.toMap(SysAddress::getCode, SysAddress::getName));
            sysPatient.setJoinCityName(addRessMap.get(sysPatient.getJoinCityId()));
            sysPatient.setJoinProvinceName(addRessMap.get(sysPatient.getJoinProvinceId()));
            sysPatient.setLiveCityName(addRessMap.get(sysPatient.getLiveCityId()));
            sysPatient.setLiveProvinceName(addRessMap.get(sysPatient.getLiveProvinceId()));
        }
        return sysPatient;
    }

    @Override
    public SysPatient checkValidateCode(String openId, String mobile, String validateCode) {
        // 验证短信验证码是否正确
        String key = RedisKeyPrefix.SMS_PREFIX + mobile;
        Object obj = redisService.get(key);
        if(Objects.isNull(obj)){
            throw new BusinessException("短信验证码已经过期，请重新获取");
        }
        if(!validateCode.equals(obj.toString())){
            throw new BusinessException("短信验证码不正确");
        }
        SysPatient sysPatient = sysPatientMapper.selectByPhone(mobile);
        if(sysPatient != null){
            List<SysAddress> sysAddresses = sysAddressService.getAll();
            Map<String, String> addRessMap = sysAddresses.stream().collect(Collectors.toMap(SysAddress::getCode, SysAddress::getName));
            sysPatient.setJoinCityName(addRessMap.get(sysPatient.getJoinCityId()));
            sysPatient.setJoinProvinceName(addRessMap.get(sysPatient.getJoinProvinceId()));
            sysPatient.setLiveCityName(addRessMap.get(sysPatient.getLiveCityId()));
            sysPatient.setLiveProvinceName(addRessMap.get(sysPatient.getLiveProvinceId()));
        }
        return sysPatient;
    }

    @Override
    public List<SysPatient> selectByHospitalIds(List<String> hospitalIds) {
        return sysPatientMapper.selectByHospitalIds(hospitalIds,new SysPatient());
    }

    @Override
    public NurseVo queryNurseByPatientOfOpenId(String openId) {
        SysPatient patient = sysPatientMapper.getPatientInfoByOpenId(openId);
        if(patient == null){
            throw new BusinessException("该患者还未入组到因你同行项目中");
        }
        if(StringUtils.isEmpty(patient.getNurseId())){
            throw new BusinessException("您的资料还未被审批，请耐心等待审批");
        }

        SysHospital sysHospital = sysHospitalService.selectByKey(patient.getHospitalId());
        if(sysHospital == null){
            throw new BusinessException("该患者绑定的医院信息不存在");
        }
        SysRangeHospital sysRangeHospital = sysRangeHospitalService.selectByHospitalId(patient.getHospitalId());
        if(sysRangeHospital == null){
            throw new BusinessException("该患者入住的医院还未绑定所属范围，请联系后台管理员进行绑定");
        }
        SysRange sysRange = sysRangeService.selectRangeByRangeId(sysRangeHospital.getRangeId());
        if(sysRange == null){
            throw new BusinessException("该患者入住的医院还未绑定所属范围，请联系后台管理员进行绑定");
        }

        SysNurse sysNurse = sysNurseService.selectById(patient.getNurseId());
        NurseVo nurseVo = new NurseVo();
        BeanUtils.copyProperties(sysNurse,nurseVo);

        List<SysAddress> sysAddresses = sysAddressService.getAll();
        Map<String, String> addRessMap = sysAddresses.stream().collect(Collectors.toMap(SysAddress::getCode, SysAddress::getName));
        nurseVo.setProvinceName(addRessMap.get(sysHospital.getProvinceCode()));
        nurseVo.setCityName(addRessMap.get(sysHospital.getCityCode()));
        nurseVo.setAreaName(addRessMap.get(sysHospital.getAreaCode()));
        nurseVo.setLatitude(sysHospital.getLatitude());
        nurseVo.setLongitude(sysHospital.getLongitude());
        return nurseVo;
    }

    @Override
    public SysPatient getPatientInfoById(String patientId) {
        SysPatient sysPatient = sysPatientMapper.getPatientInfoById(patientId);
        if(sysPatient != null){
            List<SysAddress> sysAddresses = sysAddressService.getAll();
            Map<String, String> addRessMap = sysAddresses.stream().collect(Collectors.toMap(SysAddress::getCode, SysAddress::getName));
            sysPatient.setJoinCityName(addRessMap.get(sysPatient.getJoinCityId()));
            sysPatient.setJoinProvinceName(addRessMap.get(sysPatient.getJoinProvinceId()));
            sysPatient.setLiveCityName(addRessMap.get(sysPatient.getLiveCityId()));
            sysPatient.setLiveProvinceName(addRessMap.get(sysPatient.getLiveProvinceId()));
        }
        return sysPatient;
    }


    @Override
    public List<EchartsVo> apiIndexStatistics(String openId, Integer type) {
        // 先根据openId查询护士信息
        SysNurse sysNurse = sysNurseService.selectByOpenId(openId);
        if(sysNurse == null){
            throw new BusinessException("请先前往患者管理页面进行护士信息的认证");
        }
        // 查询护士所属的范围
        SysRangeNurse sysRangeNurse = sysRangeNurseService.selectByNurseId(sysNurse.getId());
        if(sysRangeNurse == null){
            throw new BusinessException("请联系后台管理员设置您的所属范围");
        }
        List<EchartsVo> list = Lists.newArrayList();
        // 查询范围所关联的医院信息
        List<SysRangeHospital> sysRangeHospitalList = sysRangeHospitalService.selectByRangeIds(Collections.singletonList(sysRangeNurse.getRangeId()));
        List<String> hospitalIds = sysRangeHospitalList.stream().map(SysRangeHospital::getHospitalId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(hospitalIds)){
            throw new BusinessException("请联系后台管理员设置您的所属机构");
        }
        SysPatient sysPatient = new SysPatient();
        sysPatient.setPrescription(type);
        List<SysPatient> patientList = sysPatientMapper.selectByHospitalIds(hospitalIds,sysPatient);
        List<String> patientIds = patientList.stream().map(SysPatient::getId).collect(Collectors.toList());
        long newJoinGroupCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.NO.equals(f.getAuditStatus())).count();
        EchartsVo newJoinGroup = new EchartsVo();
        newJoinGroup.setName("入组患者数");
        newJoinGroup.setValue(newJoinGroupCount);
        list.add(newJoinGroup);


        long inGroupCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.YES.equals(f.getAuditStatus())).count();
        EchartsVo inGroup = new EchartsVo();
        inGroup.setName("在组患者数");
        inGroup.setValue(inGroupCount);
        list.add(inGroup);

        long exitGroupCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.TWO.equals(f.getAuditStatus())).count();
        EchartsVo exitGroup = new EchartsVo();
        exitGroup.setName("脱组患者数");
        exitGroup.setValue(exitGroupCount);
        list.add(exitGroup);

        // 查询今日待随访人数
        Long waitFollowCount = sysPatientFollowService.queryCurrentDayFollowCount(patientIds);
        EchartsVo waitFollow = new EchartsVo();
        waitFollow.setName("待随访患者数");
        waitFollow.setValue(waitFollowCount);
        list.add(waitFollow);

        long deathCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.TWO.equals(f.getAuditStatus()) && "死亡".equals(f.getRemarks())).count();
        EchartsVo death = new EchartsVo();
        death.setName("死亡");
        death.setValue(deathCount);
        list.add(death);

        long refuseServiceCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.TWO.equals(f.getAuditStatus()) && "拒绝服务".equals(f.getRemarks())).count();
        EchartsVo refuseService = new EchartsVo();
        refuseService.setName("拒绝服务");
        refuseService.setValue(refuseServiceCount);
        list.add(refuseService);

        long outOfContactCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.TWO.equals(f.getAuditStatus()) && "失联".equals(f.getRemarks())).count();
        EchartsVo outOfContact = new EchartsVo();
        outOfContact.setName("失联");
        outOfContact.setValue(outOfContactCount);
        list.add(outOfContact);

        long economicReasonsCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.TWO.equals(f.getAuditStatus()) && "经济原因".equals(f.getRemarks())).count();
        EchartsVo economicReasons = new EchartsVo();
        economicReasons.setName("经济原因");
        economicReasons.setValue(economicReasonsCount);
        list.add(economicReasons);

        return list;
    }

    @Override
    public List<BigDecimal> prescriptionsNum(String openId, StatisticsDto statisticsDto) {
        List<String> hospitalIds = Lists.newArrayList();
        if(StringUtils.isEmpty(statisticsDto.getHospitalId())){
            // 先根据openId查询护士信息
            SysNurse sysNurse = sysNurseService.selectByOpenId(openId);
            if(sysNurse == null){
                throw new BusinessException("请先前往患者管理页面进行护士信息的认证");
            }
            // 查询护士所属的范围
            SysRangeNurse sysRangeNurse = sysRangeNurseService.selectByNurseId(sysNurse.getId());
            if(sysRangeNurse == null){
                throw new BusinessException("请联系后台管理员设置您的所属范围");
            }
            // 查询范围所关联的医院信息
            List<SysRangeHospital> sysRangeHospitalList = sysRangeHospitalService.selectByRangeIds(Collections.singletonList(sysRangeNurse.getRangeId()));
            hospitalIds = sysRangeHospitalList.stream().map(SysRangeHospital::getHospitalId).collect(Collectors.toList());


        }else{
            hospitalIds.add(statisticsDto.getHospitalId());
        }
        DateTime currentMonthStartDate = DateUtil.beginOfMonth(new Date());
        DateTime currentMonthEndDate = DateUtil.endOfMonth(new Date());
        DateTime preSixMonthStartDate = DateUtil.offsetMonth(currentMonthStartDate, 6);
        List<SysPatient> patientList = sysPatientMapper.selectByHospitalIdsAndDateRange(hospitalIds,statisticsDto.getType(),preSixMonthStartDate,currentMonthEndDate);
        List<BigDecimal> counts = Lists.newArrayList();
        LocalDateTime startDateTime = DateUtil.parseLocalDateTime(DateUtil.format(preSixMonthStartDate,"yyyy-MM-dd HH:mm:ss"));
        LocalDateTime endDateTime = startDateTime.with(TemporalAdjusters.lastDayOfMonth());
        for (int i = 0; i < 6; i++) {
            LocalDateTime finalStartDateTime = startDateTime;
            LocalDateTime finalEndDateTime = endDateTime;
            long count = patientList.stream().filter(f -> DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isAfter(finalStartDateTime)
                    && DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isBefore(finalEndDateTime)).count();

            counts.add(new BigDecimal(count));
            startDateTime = startDateTime.plusMonths(1).with(TemporalAdjusters.firstDayOfMonth());
            endDateTime = startDateTime.with(TemporalAdjusters.lastDayOfMonth());
        }
        return counts;
    }

    @Override
    public List<BigDecimal> prescriptionsPercentage(String openId, StatisticsDto statisticsDto) {
        List<String> hospitalIds = Lists.newArrayList();
        if(StringUtils.isEmpty(statisticsDto.getHospitalId())){
            // 先根据openId查询护士信息
            SysNurse sysNurse = sysNurseService.selectByOpenId(openId);
            if(sysNurse == null){
                throw new BusinessException("请先前往患者管理页面进行护士信息的认证");
            }
            // 查询护士所属的范围
            SysRangeNurse sysRangeNurse = sysRangeNurseService.selectByNurseId(sysNurse.getId());
            if(sysRangeNurse == null){
                throw new BusinessException("请联系后台管理员设置您的所属范围");
            }
            // 查询范围所关联的医院信息
            List<SysRangeHospital> sysRangeHospitalList = sysRangeHospitalService.selectByRangeIds(Collections.singletonList(sysRangeNurse.getRangeId()));
            hospitalIds = sysRangeHospitalList.stream().map(SysRangeHospital::getHospitalId).collect(Collectors.toList());


        }else{
            hospitalIds.add(statisticsDto.getHospitalId());
        }
        DateTime currentMonthStartDate = DateUtil.beginOfMonth(new Date());
        DateTime currentMonthEndDate = DateUtil.endOfMonth(new Date());
        DateTime preSixMonthStartDate = DateUtil.offsetMonth(currentMonthStartDate, 6);
        List<SysPatient> patientList = sysPatientMapper.selectByHospitalIdsAndDateRange(hospitalIds,null, preSixMonthStartDate,currentMonthEndDate);
        List<BigDecimal> counts = Lists.newArrayList();
        LocalDateTime startDateTime = DateUtil.parseLocalDateTime(DateUtil.format(preSixMonthStartDate,"yyyy-MM-dd HH:mm:ss"));
        LocalDateTime endDateTime = startDateTime.with(TemporalAdjusters.lastDayOfMonth());
        for (int i = 0; i < 6; i++) {
            LocalDateTime finalStartDateTime = startDateTime;
            LocalDateTime finalEndDateTime = endDateTime;
            long totalCount = patientList.stream().filter(f -> DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isAfter(finalStartDateTime)
                    && DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isBefore(finalEndDateTime)).count();

            long count = patientList.stream().filter(f -> DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isAfter(finalStartDateTime)
                    && DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isBefore(finalEndDateTime)
                    && statisticsDto.getType().equals(f.getPrescription())).count();
            if(totalCount != 0L){
                counts.add(new BigDecimal(count).divide(new BigDecimal(totalCount)).multiply(new BigDecimal("100")));
            }else{
                counts.add(BigDecimal.ZERO);
            }
            startDateTime = startDateTime.plusMonths(1).with(TemporalAdjusters.firstDayOfMonth());
            endDateTime = startDateTime.with(TemporalAdjusters.lastDayOfMonth());
        }
        return counts;
    }

    @Override
    public ChangeReasonVo changeReason(String openId) {
        ChangeReasonVo changeReasonVo = new ChangeReasonVo();
        // 先根据openId查询护士信息
        SysNurse sysNurse = sysNurseService.selectByOpenId(openId);
        if(sysNurse == null){
            throw new BusinessException("请先前往患者管理页面进行护士信息的认证");
        }
        // 查询护士所属的范围
        SysRangeNurse sysRangeNurse = sysRangeNurseService.selectByNurseId(sysNurse.getId());
        if(sysRangeNurse == null){
            throw new BusinessException("请联系后台管理员设置您的所属范围");
        }
        // 查询范围所关联的医院信息
        List<SysRangeHospital> sysRangeHospitalList = sysRangeHospitalService.selectByRangeIds(Collections.singletonList(sysRangeNurse.getRangeId()));
        List<String> hospitalIds = sysRangeHospitalList.stream().map(SysRangeHospital::getHospitalId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(hospitalIds)){
            throw new BusinessException("请联系后台管理员设置您的所属机构");
        }
        List<SysPatient> patientList = sysPatientMapper.selectByHospitalIds(hospitalIds,new SysPatient());
        changeReasonVo.setProjectService(new BigDecimal(patientList.stream().filter(f -> "项目服务".equals(f.getChangeReason())).count()));
        changeReasonVo.setAdvocacy(new BigDecimal(patientList.stream().filter(f -> "患教会".equals(f.getChangeReason())).count()));
        changeReasonVo.setJoinPAP(new BigDecimal(patientList.stream().filter(f -> "PAP".equals(f.getChangeReason())).count()));
        changeReasonVo.setFollowDoctorSPrescription(new BigDecimal(patientList.stream().filter(f -> "遵医嘱".equals(f.getChangeReason())).count()));
        return changeReasonVo;
    }

    @Override
    public List<EchartsVo> sysIndexStatistics(Integer type) {
        List<EchartsVo> list = Lists.newArrayList();
        // 查询范围所关联的医院信息
        List<SysRangeHospital> sysRangeHospitalList = sysRangeHospitalService.selectAll();
        if(CollectionUtils.isEmpty(sysRangeHospitalList)){
            throw new BusinessException("所属范围未设置，请先设定管理范围");
        }
        List<String> hospitalIds = sysRangeHospitalList.stream().map(SysRangeHospital::getHospitalId).collect(Collectors.toList());

        SysPatient sysPatient = new SysPatient();
        sysPatient.setPrescription(type);
        List<SysPatient> patientList = sysPatientMapper.selectByHospitalIds(hospitalIds,sysPatient);
        List<String> patientIds = patientList.stream().map(SysPatient::getId).collect(Collectors.toList());
        long newJoinGroupCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.NO.equals(f.getAuditStatus())).count();
        EchartsVo newJoinGroup = new EchartsVo();
        newJoinGroup.setName("入组患者数");
        newJoinGroup.setValue(newJoinGroupCount);
        list.add(newJoinGroup);


        long inGroupCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.YES.equals(f.getAuditStatus())).count();
        EchartsVo inGroup = new EchartsVo();
        inGroup.setName("在组患者数");
        inGroup.setValue(inGroupCount);
        list.add(inGroup);

        long exitGroupCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.TWO.equals(f.getAuditStatus())).count();
        EchartsVo exitGroup = new EchartsVo();
        exitGroup.setName("脱组患者数");
        exitGroup.setValue(exitGroupCount);
        list.add(exitGroup);

        // 查询今日待随访人数
        Long waitFollowCount = sysPatientFollowService.queryCurrentDayFollowCount(patientIds);
        EchartsVo waitFollow = new EchartsVo();
        waitFollow.setName("待随访患者数");
        waitFollow.setValue(waitFollowCount);
        list.add(waitFollow);

        long deathCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.TWO.equals(f.getAuditStatus()) && "死亡".equals(f.getRemarks())).count();
        EchartsVo death = new EchartsVo();
        death.setName("死亡");
        death.setValue(deathCount);
        list.add(death);

        long refuseServiceCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.TWO.equals(f.getAuditStatus()) && "拒绝服务".equals(f.getRemarks())).count();
        EchartsVo refuseService = new EchartsVo();
        refuseService.setName("拒绝服务");
        refuseService.setValue(refuseServiceCount);
        list.add(refuseService);

        long outOfContactCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.TWO.equals(f.getAuditStatus()) && "失联".equals(f.getRemarks())).count();
        EchartsVo outOfContact = new EchartsVo();
        outOfContact.setName("失联");
        outOfContact.setValue(outOfContactCount);
        list.add(outOfContact);


        long economicReasonsCount = patientList.stream().filter(f -> Constants.YES.equals(f.getStatus()) && Constants.TWO.equals(f.getAuditStatus()) && "经济原因".equals(f.getRemarks())).count();
        EchartsVo economicReasons = new EchartsVo();
        economicReasons.setName("经济原因");
        economicReasons.setValue(economicReasonsCount);
        list.add(economicReasons);

        return list;
    }

    @Override
    public List<BigDecimal> sysPrescriptionsNum(StatisticsDto statisticsDto) {
        List<String> hospitalIds = Lists.newArrayList();
        if(StringUtils.isEmpty(statisticsDto.getHospitalId())){
            List<SysRangeHospital> sysRangeHospitalList = sysRangeHospitalService.selectAll();
            if(CollectionUtils.isEmpty(sysRangeHospitalList)){
                throw new BusinessException("所属范围未设置，请先设定管理范围");
            }
            hospitalIds = sysRangeHospitalList.stream().map(SysRangeHospital::getHospitalId).collect(Collectors.toList());
        }else{
            hospitalIds.add(statisticsDto.getHospitalId());
        }
        DateTime currentMonthStartDate = DateUtil.beginOfMonth(new Date());
        DateTime currentMonthEndDate = DateUtil.endOfMonth(new Date());
        DateTime preSixMonthStartDate = DateUtil.offsetMonth(currentMonthStartDate, 6);
        List<SysPatient> patientList = sysPatientMapper.selectByHospitalIdsAndDateRange(hospitalIds,statisticsDto.getType(),preSixMonthStartDate,currentMonthEndDate);
        List<BigDecimal> counts = Lists.newArrayList();
        LocalDateTime startDateTime = DateUtil.parseLocalDateTime(DateUtil.format(preSixMonthStartDate,"yyyy-MM-dd HH:mm:ss"));
        LocalDateTime endDateTime = startDateTime.with(TemporalAdjusters.lastDayOfMonth());
        for (int i = 0; i < 6; i++) {
            LocalDateTime finalStartDateTime = startDateTime;
            LocalDateTime finalEndDateTime = endDateTime;
            long count = patientList.stream().filter(f -> DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isAfter(finalStartDateTime)
                    && DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isBefore(finalEndDateTime)).count();

            counts.add(new BigDecimal(count));
            startDateTime = startDateTime.plusMonths(1).with(TemporalAdjusters.firstDayOfMonth());
            endDateTime = startDateTime.with(TemporalAdjusters.lastDayOfMonth());
        }
        return counts;
    }

    @Override
    public List<BigDecimal> sysPrescriptionsPercentage(StatisticsDto statisticsDto) {
        List<String> hospitalIds = Lists.newArrayList();
        if(StringUtils.isEmpty(statisticsDto.getHospitalId())){
            // 查询范围所关联的医院信息
            List<SysRangeHospital> sysRangeHospitalList = sysRangeHospitalService.selectAll();
            if(CollectionUtils.isEmpty(sysRangeHospitalList)){
                throw new BusinessException("所属范围未设置，请先设定管理范围");
            }
            hospitalIds = sysRangeHospitalList.stream().map(SysRangeHospital::getHospitalId).collect(Collectors.toList());
        }else{
            hospitalIds.add(statisticsDto.getHospitalId());
        }
        DateTime currentMonthStartDate = DateUtil.beginOfMonth(new Date());
        DateTime currentMonthEndDate = DateUtil.endOfMonth(new Date());
        DateTime preSixMonthStartDate = DateUtil.offsetMonth(currentMonthStartDate, 6);
        List<SysPatient> patientList = sysPatientMapper.selectByHospitalIdsAndDateRange(hospitalIds,null, preSixMonthStartDate,currentMonthEndDate);
        List<BigDecimal> counts = Lists.newArrayList();
        LocalDateTime startDateTime = DateUtil.parseLocalDateTime(DateUtil.format(preSixMonthStartDate,"yyyy-MM-dd HH:mm:ss"));
        LocalDateTime endDateTime = startDateTime.with(TemporalAdjusters.lastDayOfMonth());
        for (int i = 0; i < 6; i++) {
            LocalDateTime finalStartDateTime = startDateTime;
            LocalDateTime finalEndDateTime = endDateTime;
            long totalCount = patientList.stream().filter(f -> DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isAfter(finalStartDateTime)
                    && DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isBefore(finalEndDateTime)).count();

            long count = patientList.stream().filter(f -> DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isAfter(finalStartDateTime)
                    && DateUtil.parseLocalDateTime(DateUtil.format(f.getPrescriptionTime(),"yyyy-MM-dd HH:mm:ss")).isBefore(finalEndDateTime)
                    && statisticsDto.getType().equals(f.getPrescription())).count();
            if(totalCount != 0L){
                counts.add(new BigDecimal(count).divide(new BigDecimal(totalCount)).multiply(new BigDecimal("100")));
            }else{
                counts.add(BigDecimal.ZERO);
            }
            startDateTime = startDateTime.plusMonths(1).with(TemporalAdjusters.firstDayOfMonth());
            endDateTime = startDateTime.with(TemporalAdjusters.lastDayOfMonth());
        }
        return counts;
    }

    @Override
    public ChangeReasonVo sysChangeReason() {
        ChangeReasonVo changeReasonVo = new ChangeReasonVo();
        List<SysRangeHospital> sysRangeHospitalList = sysRangeHospitalService.selectAll();
        if(CollectionUtils.isEmpty(sysRangeHospitalList)){
            throw new BusinessException("所属范围未设置，请先设定管理范围");
        }
        List<String> hospitalIds = sysRangeHospitalList.stream().map(SysRangeHospital::getHospitalId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(hospitalIds)){
            throw new BusinessException("范围下的所属机构为空");
        }
        List<SysPatient> patientList = sysPatientMapper.selectByHospitalIds(hospitalIds,new SysPatient());
        changeReasonVo.setProjectService(new BigDecimal(patientList.stream().filter(f -> "项目服务".equals(f.getChangeReason())).count()));
        changeReasonVo.setAdvocacy(new BigDecimal(patientList.stream().filter(f -> "患教会".equals(f.getChangeReason())).count()));
        changeReasonVo.setJoinPAP(new BigDecimal(patientList.stream().filter(f -> "PAP".equals(f.getChangeReason())).count()));
        changeReasonVo.setFollowDoctorSPrescription(new BigDecimal(patientList.stream().filter(f -> "遵医嘱".equals(f.getChangeReason())).count()));
        return changeReasonVo;
    }

    @Override
    @Transactional
    public void checkPatient(SysPatient sysPatient) throws Exception {
        if(StringUtils.isEmpty(sysPatient.getId())){
            throw new BusinessException("患者id不能为空");
        }
        SysPatient patient = sysPatientMapper.getPatientInfoById(sysPatient.getId());
        if(patient == null){
            throw new BusinessException("患者信息不存在");
        }
        if(Constants.YES.equals(patient.getJoinType()) && StringUtils.isEmpty(patient.getOpenId())){
            throw new BusinessException("该患者本人还未签署协议，不能进行审批");
        }
        if(Constants.NO.equals(patient.getJoinType()) && StringUtils.isEmpty(patient.getOpenId())){
            // 护士代替签署协议
            extracted(sysPatient.getUpdateBy(),sysPatient.getUpdater(),sysPatient);
        }
        sysPatient.setStatus(Constants.YES);
        sysPatient.setUpdateDate(new Date());
        sysPatientMapper.updateByPrimaryKeySelective(sysPatient);
    }

    @Override
    public List<PrescriptionStatisticsVo> exportPrescriptionStatistics(DayReportQueryParam dayReportQueryParam) {
        return sysPatientMapper.exportPrescriptionStatistics(dayReportQueryParam);
    }

    @Override
    public List<NewJoinGroupStatistics> exportNewJoinGroup(DayReportQueryParam dayReportQueryParam) {
        List<NewJoinGroupStatistics> newJoinGroupStatistics = sysPatientMapper.exportNewJoinGroup(dayReportQueryParam);
        if(!CollectionUtils.isEmpty(newJoinGroupStatistics)){
            List<SysAddress> sysAddresses = sysAddressService.getAll();
            Map<String, String> addResMap = sysAddresses.stream().collect(Collectors.toMap(SysAddress::getCode, SysAddress::getName));
            for (NewJoinGroupStatistics newJoinGroupStatistic : newJoinGroupStatistics) {
                newJoinGroupStatistic.setJoinCityName(addResMap.get(newJoinGroupStatistic.getJoinCityId()));
                newJoinGroupStatistic.setJoinProvinceName(addResMap.get(newJoinGroupStatistic.getJoinProvinceId()));
            }
        }
        return newJoinGroupStatistics;
    }

    @Override
    public List<FollowStatistics> selectAllNurse() {
        return sysPatientMapper.selectAllNurse();
    }

    @Override
    public void batchUpdateNurseId(List<String> patientIds, String nurseId) {
        sysPatientMapper.batchUpdateNurseId(patientIds,nurseId);
    }

    @Override
    @Transactional
    public int deletePatient(String id) {
        SysPatient patient = sysPatientMapper.getPatientInfoById(id);
        if(patient == null){
            throw new BusinessException("患者信息不存在");
        }
        patient.setUpdateDate(new Date());
        patient.setDelFlag(Constants.DELETE_YES);
        sysPatientMapper.updateByPrimaryKeySelective(patient);
        sysPatientFollowService.deletePatientFollowByPatientId(id);
        return 1;
    }

    @Override
    public List<SysPatient> selectByIds(List<String> patientIds) {
        return sysPatientMapper.selectByIds(patientIds);
    }


}
